#!/usr/bin/env python
# -*- coding: utf-8 -*-

from django.http import HttpResponseRedirect
from django.shortcuts import redirect
from django.contrib.auth import authenticate, login
from django.contrib.auth.models import User
from django.contrib.auth.decorators import login_required
from django.core.mail import EmailMessage
from django.core.urlresolvers import reverse
from shared.helper import render_to_response
from usermanagement.forms import LoginForm, RegisterForm,\
    ChangePasswordForm, LostPasswordForm, LostPasswordActivationForm,\
    AcceptRulesForm
from usermanagement.models import UserProfile
from django.core.exceptions import ObjectDoesNotExist
import settings
from django.forms.forms import Form

@login_required
def index(request):
    """
    A small view that displays a list of all users.
    See the template for the truely cool stuff.
    """
    users = User.objects.all().order_by('first_name', 'last_name')

    return render_to_response(request, 'usermanagement/index.html',
                                {'users' : users}) 

#class LoginWizard(FormWizard):
#    def done(self, form_list, **kwargs):
#        return render_to_response('done.html', {
#            'form_data': [form.cleaned_data for form in form_list],
#        })
#        
#    def process_step(self, request, form, step):
#        if(step == 1):
#            #form.
#        
#    def get_template_names(self, step):
#        return ['usermanagement/accept_rules.html']

def loginview(request):
    """
    This view logs the user in.
    It has basicly 2 usage scenarios :
        1. A user uses the Loginform display on every page.
        So this view is requested via POST, username and password are checked
        and the user will be redirected to page whre he used the form.
        
        2. A logged out user tries to access a view protected by @login_required
        In this case @login_required will redirect him to this view via GET with
        next as a parameter.
        In this case a message asking the user ot log in will be displayed.
        The loginform context preprocessor will take the next from the GET request 
        and include it in the login form.
        Check usermanagment/context_processors.py for more information about,
        this mechanism.
        The rest is handled as described in 1. 
        
        For more information about loggin users in see :
        
    """
    if request.method == 'GET':
        return render_to_response(request, 'usermanagement/login.html')

    
    login_form = LoginForm(request.POST)
    
    if not login_form.is_valid():
        return render_to_response(request, 'usermanagement/error.html', {
            'error_message' : 'Bitte korrekten Username und Password eingeben.'})
    

    next_page = login_form.cleaned_data['next_page']
    username = login_form.cleaned_data['username']
    password = login_form.cleaned_data['password']
    
    user = authenticate(username=username,password=password)
    
    if not user == None:

        if user.is_active:
            try:
                profile = user.get_profile()
                if not profile.activation_hash == '': # in case a user has lost his password but found again before changing it (hash!='' && active)
                    profile.activation_hash = ''
                    profile.save()
                if not profile.accepted_rules:
                    return accept_rules(request)
            except UserProfile.DoesNotExist:
                return accept_rules(request)
                
            login(request,user)
            return redirect(next_page)
        else:
            return render_to_response(request, 'usermanagement/error.html', {
            'error_message' : 'User noch nicht aktiv.', 'back_link' : next_page})
    else: 
        return render_to_response(request, 'usermanagement/error.html', {
        'error_message' : 'User oder Passwort unbekannt.'})
        
def accept_rules(request):
    # test if the post comes from this view or from the login view
    this_view = False
    for key, _ in request.POST.items():
        if key == 'first_name':
            this_view = True
            
    if (request.method == 'POST') and this_view: # If the form has been submitted from this view...
        login_form = LoginForm(request.POST)
        accept_form = AcceptRulesForm(request.POST)
        accept_form.user = request.user
        if login_form.is_valid() and accept_form.is_valid(): # All validation rules pass
            username = login_form.cleaned_data['username']
            password = login_form.cleaned_data['password']
            
            new_username = accept_form.cleaned_data['new_username']
            
            first_name = accept_form.cleaned_data['first_name']
            last_name = accept_form.cleaned_data['last_name']
            
            accept_rules = accept_form.cleaned_data['accept_rules']
            
            user = authenticate(username=username,password=password)
            
            if user == None:
                return render_to_response(request, 'usermanagement/error.html', {
                'error_message' : 'User oder Passwort unbekannt.'})
                
            if not user.is_active:
                return render_to_response(request, 'usermanagement/error.html', {
                'error_message' : 'User noch nicht aktiv.'})
                
            user.username = new_username
            
            user.first_name = first_name
            user.last_name = last_name
            
            user.save()
            
            try:
                profile = user.get_profile()
            except ObjectDoesNotExist:
                profile = UserProfile(
                                        user = user
                                     )
            
            profile.accepted_rules = accept_rules
            
            profile.save()
            
            login(request,user)
            
            return redirect(reverse('shared.views.index'))

                
    else:
        login_form = LoginForm(request.POST)
        accept_form = AcceptRulesForm()

    return render_to_response(request, 'usermanagement/accept_rules.html', {
        'login_form': login_form,
        'accept_form': accept_form,
    })

def registerview(request):
    if request.user.is_authenticated(): # already logged-in users should not be here => redirect to their profile
        return HttpResponseRedirect('/')
    if request.method == 'POST': # If the form has been submitted...
        form = RegisterForm(request.POST,request.FILES)
        if form.is_valid(): # All validation rules pass
            
            username = form.cleaned_data['username']
            
            email = form.cleaned_data['email']
            password = form.cleaned_data['password']
            
            first_name = form.cleaned_data['first_name']
            last_name = form.cleaned_data['last_name']
            
            accepted_rules = form.cleaned_data['accept_rules']
            
            user = User.objects.create_user(username, email, password)
            
            user.first_name = first_name
            user.last_name = last_name
            
            user.is_active = False
            
            user.save()
            
            # set the profile
            activation_hash = UserProfile.generate_activation_hash()
            
            profile = UserProfile(
                                    user = user,
                                    activation_hash = activation_hash,
                                    accepted_rules = accepted_rules
                                 )
            profile.save(user)
            
            # build an absolute activation link
            activation_link = request.build_absolute_uri(reverse('usermanagement.views.activationview', kwargs={ 'email': email, 'activation_hash': activation_hash }))

            __send_activation_email(user, activation_link)
                        
            return render_to_response(request, 'usermanagement/register_complete.html')
    else:
        form = RegisterForm()

    return render_to_response(request, 'usermanagement/register.html', {
        'form': form,
    })
    
@login_required
def delete_user(request, user_id):
    """
    View for deleting a User
    """
    
    user = User.objects.get(id = user_id)
    
    if not (request.user.has_perm('auth.delete_user') or request.user.id == user.id):
        return redirect(settings.LOGIN_URL)
    
    if request.method == 'POST':
        user.delete()
        return redirect('/')
    
    form = Form()
    return render_to_response(
                                request,
                                'usermanagement/delete_user.html',
                                {
                                    'form': form,
                                    'user': user
                                }
                             )
    
    
def activationview(request, activation_hash = '', email = ''):
    """ Deals with the activation of a User """
    try:
        user = User.objects.get(email=email)
    except User.DoesNotExist: # if the user does not exist render an error
        return render_to_response(request, 'usermanagement/error.html', {
            'error_message' : 'User existiert nicht. Bitte Admin kontaktieren.'})

    try:
        profile = user.get_profile()
    except UserProfile.DoesNotExist: # if there is no profile existent (which should NEVER EVER happen) render an error
        return render_to_response(request, 'usermanagement/error.html', {
            'error_message' : 'Profil für ' + user.username + ' existiert nicht ' + '. Bitte Admin kontaktieren.'})
    
    if profile.activation_hash == '': # if the hash is '' then the user has already been activated: render complete page in order to tell the user that the activation was successful
        return render_to_response(request, 'usermanagement/error.html', {
            'error_message' : 'User ' + user.username + ' ist schon aktiv'})
    
    if profile.activation_hash == activation_hash: # if the hash is equal to the real one: activate user, set hash to '' and render complete
        user.is_active = True
        user.save()
        profile.activation_hash = ''
        profile.save()
        return render_to_response(request, 'usermanagement/activation_complete.html', {
            'username':user,
            'activation_hash':activation_hash
        })
    return render_to_response(request, 'usermanagement/error.html', {
        'error_message' : 'User existiert nicht ' + user.username + ' mit Hash ' + activation_hash + '. Bitte Admin kontaktieren.'})

@login_required
def changepasswordview(request):
    if request.method == 'POST': # If the form has been submitted...
        form = ChangePasswordForm(request.POST)
        form.user = request.user
        if form.is_valid(): # All validation rules pass

            user = request.user
            
            # set new password
            user.set_password(form.cleaned_data['password']) # known to be valid (made sure in the form)
            
            user.save()
            
            return redirect("/")
    else:
        form = ChangePasswordForm() # An unbound form
        form.user = request.user

    return render_to_response(request, 'usermanagement/change_password.html', {
        'form': form,
    })

def lostpasswordview(request):
    """ This view is there to display the LostPasswordForm and send the reactivation mail """
    if request.method == 'POST': # If the form has been submitted...
        form = LostPasswordForm(request.POST)
        if form.is_valid(): # All validation rules pass
            email = form.cleaned_data['email']
            
            user = User.objects.get(email = email)
            
            activation_hash = UserProfile.generate_activation_hash()
            
            try:
                profile = user.get_profile()
            except ObjectDoesNotExist:
                profile = UserProfile(
                                        user = user
                                     )
                
            
            profile.activation_hash = activation_hash
            
            profile.save()
            
            # build an absolute activation link
            activation_link = request.build_absolute_uri(reverse('usermanagement.views.lostpasswordactivation', kwargs={ 'email': email, 'activation_hash': activation_hash }))
            
            __send_lostpassword_email(user, activation_link)
            
            return redirect("/")
    else:
        form = LostPasswordForm() # An unbound form

    return render_to_response(request, 'usermanagement/lost_password_form.html', {
        'form': form,
    })
    
def lostpasswordactivation(request, email = '', activation_hash = ''):
    """ Deals with the reactivation of a User """
    if request.method == 'POST': 
        form = LostPasswordActivationForm(request.POST)
        if form.is_valid(): # All validation rules pass
            user = None
            
            try:
                user = User.objects.get(email = email)
            except User.DoesNotExist: # if the user does not exist render an error
                return render_to_response(request, 'usermanagement/error.html', {
                    'error_message' : 'User existiert nicht. Bitte Admin kontaktieren.'})
            try:
                profile = user.get_profile()
            except UserProfile.DoesNotExist: # if there is no profile existent (which should NEVER EVER happen) render an error
                return render_to_response(request, 'usermanagement/error.html', {
                    'error_message' : 'Profil für ' + email + ' existiert nicht ' + '. Bitte Admin kontaktieren.'})
            if profile.activation_hash == '': # if the hash is '' then the user has already been activated: render complete page in order to tell the user that the activation was successful
                return render_to_response(request, 'usermanagement/error.html', {
                    'error_message' : 'User ' + email + ' ist schon reaktiviert worden.'})
            
            if profile.activation_hash == activation_hash: # if the hash is equal to the real one: set new password
                if user.is_active: # if the user is active do it
                    user.set_password(form.cleaned_data['password']) # known to be valid (made sure in the form)
                    user.save()
                    profile.activation_hash = ''
                    profile.save()
                
                    return render_to_response(request, 'usermanagement/lost_password_activation_complete.html')
                else: #if not: the user has not been activated => do nothing
                    return render_to_response(request, 'usermanagement/error.html', {
                        'error_message' : 'Der User wurde noch nicht aktiviert!'})
            else: # happens if a wrong hash is entered
                return render_to_response(request, 'usermanagement/error.html', {'error_message' : 'Du bist so ein 1337 Haxor, mensch... Wenn nicht: Bitte an Admins wenden.'})
    else:
        form = LostPasswordActivationForm() # An unbound form

    return render_to_response(request, 'usermanagement/lost_password_activation_form.html', {
        'form': form,
        'email': email,
        'activation_hash': activation_hash
    })

def __send_activation_email(user, activation_link):
    welcome_mail = EmailMessage('Aktivierungs-Link für campusshare.org', # Header
        'Hallo!\n\nDu hast dich auf campusshare.org angemeldet. \
        Um deinen Account freizuschalten, rufe bitte diese Url auf:\n ' + activation_link + '\n.',
        'TomLottermann@googlemail.com', # From
        [user.email] # To
    )
    
    welcome_mail.send()
    
def __send_lostpassword_email(user, activation_link):
     
    lost_password_mail = EmailMessage('Passwort verloren auf campusshare.org', # Header
        'Hallo!\n\n \
        Um ein neues Passwort zu setzen, rufe bitte diese Url auf:\n ' + activation_link + '\n.',
        'TomLottermann@googlemail.com', # From
        [user.email] # To
    )
    
    lost_password_mail.send()
